package com.jingdianjichi.subject.infra.basic.service.impl;

import com.jingdianjichi.subject.infra.basic.entity.SearchResult;
import com.jingdianjichi.subject.infra.basic.entity.SubjectEsDoc;
import com.jingdianjichi.subject.infra.basic.entity.SubjectEsDocRequstion;
import com.jingdianjichi.subject.infra.basic.service.SearchFromEs;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SearchFromEsImpl implements SearchFromEs {

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public SearchResult<SubjectEsDoc> search(SubjectEsDocRequstion subjectEsDocRequstion) {
        try {
            // 获取参数
            log.info("从ES查询题目,keyword:{}", subjectEsDocRequstion.getKeyWord());
            String keyword = subjectEsDocRequstion.getKeyWord();
            Integer pageNo = subjectEsDocRequstion.getPageNo();
            Integer pageSize = subjectEsDocRequstion.getPageSize();
            // 构建查询条件
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            // 过滤
//            boolQueryBuilder.filter(QueryBuilders.termQuery("isDeleted", 0));
            // 根据关键词检索
            if (StringUtils.isNotBlank(keyword)) {
                boolQueryBuilder.should(QueryBuilders.matchQuery("subjectName", keyword));
                boolQueryBuilder.should(QueryBuilders.matchQuery("subjectAnswer", keyword));
            }
            // 分页
            PageRequest pageRequest = PageRequest.of(pageNo - 1, pageSize);
            // 构造查询
            NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                    .withFilter(boolQueryBuilder)
                    .withPageable(pageRequest)
                    .build();
            // 执行查询
            log.info("开始执行查询,query:{}", searchQuery);
            SearchHits<SubjectEsDoc> searchHits = elasticsearchRestTemplate.search(searchQuery, SubjectEsDoc.class);
            log.info("查询完成,total:{},查询出的数据:{}", searchHits.getTotalHits(), searchHits.getSearchHits());
            if (searchHits.getTotalHits() == 0) {
                return new SearchResult<>(Collections.emptyList(), 0L);
            }
            // === ✅ 结果处理：对 keyword 做高亮替换 ===
            List<SubjectEsDoc> resultList = searchHits.getSearchHits().stream()
                    .map(hit -> {
                        SubjectEsDoc doc = hit.getContent();
                        if (StringUtils.isNotBlank(keyword)) {
                            doc.setSubjectName(highlightKeyword(doc.getSubjectName(), keyword));
                            doc.setSubjectAnswer(highlightKeyword(doc.getSubjectAnswer(), keyword));
                        }
                        return doc;
                    })
                    .collect(Collectors.toList());
            
            // 返回包含总记录数的搜索结果
            return new SearchResult<>(resultList, searchHits.getTotalHits());
        } catch (Exception e) {
            log.error("从ES查询题目失败,keyword:{}, 错误类型:{}, 错误信息:{}", 
                      subjectEsDocRequstion.getKeyWord(), e.getClass().getSimpleName(), e.getMessage(), e);
            throw new RuntimeException("从ES查询题目失败: " + e.getMessage());
        }
    }

    /**
     * 对指定关键词进行高亮包装
     */
    private String highlightKeyword(String text, String keyword) {
        if (StringUtils.isBlank(text) || StringUtils.isBlank(keyword)) {
            return text;
        }
        // (?i) 表示忽略大小写匹配，Pattern.quote 避免正则特殊字符问题
        return text.replaceAll("(?i)" + Pattern.quote(keyword),
                "<em>" + keyword + "</em>");
    }

    @Override
    public Boolean insertToEs(SubjectEsDoc subjectEsDoc) {
        try {
            log.info("开始插入ES文档,doc:{}", subjectEsDoc);
            elasticsearchRestTemplate.save(subjectEsDoc);
            log.info("插入ES文档成功,doc:{}", subjectEsDoc);
            return true;
        } catch (Exception e) {
            log.error("插入ES文档失败,doc:{}", subjectEsDoc,e);
            throw new RuntimeException("插入ES文档失败");
        }
    }

    @Override
    public Boolean updateToEs(SubjectEsDoc subjectEsDoc) {
        try {
            log.info("开始更新ES文档,doc:{}", subjectEsDoc);
            elasticsearchRestTemplate.save(subjectEsDoc);
            log.info("更新ES文档成功,doc:{}", subjectEsDoc);
            return true;
        } catch (Exception e) {
            log.error("更新ES文档失败,doc:{}", subjectEsDoc,e);
            throw new RuntimeException("更新ES文档失败");
        }
    }

    @Override
    public Boolean deleteToEs(SubjectEsDoc subjectEsDoc) {
        try {
            log.info("开始删除ES文档,doc:{}", subjectEsDoc);
            elasticsearchRestTemplate.delete(subjectEsDoc);
            log.info("删除ES文档成功,doc:{}", subjectEsDoc);
            return true;
        } catch (Exception e) {
            log.error("删除ES文档失败,doc:{}", subjectEsDoc,e);
            throw new RuntimeException("删除ES文档失败");
        }
    }

    @Override
    public Boolean createIndex(String indexName) {
        try {
            log.info("开始创建索引,indexName:{}", indexName);
            IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(IndexCoordinates.of(indexName));
            indexOperations.create();
            log.info("创建索引成功,indexName:{}", indexName);
            return true;
        } catch (Exception e) {
            log.error("创建索引失败,indexName:{}", indexName,e);
            throw new RuntimeException("创建索引失败");
        }
    }
}
